package spynx.desl.runtime.impl;

import java.lang.reflect.Constructor;

import spynx.desl.Proxy;
import spynx.desl.runtime.IConfigurableProxy;
import spynx.desl.runtime.IContextAware;
import spynx.desl.runtime.IExecutionContext;
import spynx.desl.runtime.IProxyFactory;
import spynx.desl.runtime.IVariable;
import spynx.util.DeslRuntimeUtil;

public class ProxyFactory implements IProxyFactory {

	@Override
	public Object createObject(IExecutionContext context, Proxy proxy, Object... args) {
		try {
			Class<?> clazz = Class.forName(proxy.getBaseClass());
			
			 Object instance = args.length == 0 ? clazz.newInstance() : null;
			 if (instance == null) {
				 Constructor<?> ctor = DeslRuntimeUtil.findConstructor(clazz, args);
				 if (ctor == null)
					 throw new RuntimeException(String.format("Cannot find appropriate constructor for type '%s'.",
							 proxy.getBaseClass()));
				 instance = ctor.newInstance(args);
			 }
			 if (instance instanceof IConfigurableProxy)
				 ((IConfigurableProxy) instance).setProxyInfo(proxy);
			 if (instance instanceof IContextAware)
				 ((IContextAware) instance).setContext(context);
			 return instance;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public static Object unwrapProxy(IExecutionContext context, Proxy proxy, Object...args) {
		try {
			IVariable factoryVar = context.getRootContext().Variables().getVariable(proxy.getFactory());
			IProxyFactory factory = null;
			if (factoryVar == null) {
				Class<?> factoryClazz = Class.forName(proxy.getFactory());
				factory = (IProxyFactory) factoryClazz.newInstance();
				context.getRootContext().Variables().addVariable(new Variable(proxy.getFactory(), factory));
			}
			else
				factory = (IProxyFactory) factoryVar.getValue();
			return factory.createObject(context, proxy, args);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}
